package com.brainhealth.customer.service.impl;

import cn.hutool.poi.excel.ExcelUtil;
import cn.hutool.poi.excel.ExcelWriter;
import com.brainhealth.common.config.RuoYiConfig;
import com.brainhealth.common.constant.Constants;
import com.brainhealth.common.constant.NumberConstants;
import com.brainhealth.common.constant.PunctuationConstants;
import com.brainhealth.common.enums.AgeGroupEnum;
import com.brainhealth.common.enums.PayStatus;
import com.brainhealth.common.enums.SexEnum;
import com.brainhealth.common.utils.AesUtils;
import com.brainhealth.common.utils.DateUtils;
import com.brainhealth.common.utils.ListUtil;
import com.brainhealth.common.utils.StringUtils;
import com.brainhealth.common.utils.ip.IpUtils;
import com.brainhealth.customer.domain.*;
import com.brainhealth.customer.domain.vo.*;
import com.brainhealth.customer.mapper.*;
import com.brainhealth.customer.service.*;
import com.brainhealth.utils.CommonUtils;
import com.google.common.collect.Sets;
import io.jsonwebtoken.lang.Assert;
import org.apache.commons.collections.CollectionUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.File;
import java.math.BigDecimal;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 埋点记录Service业务层处理
 *
 * @author ruoyi
 * @date 2023-07-24
 */
@Service
public class SysBuriedPointServiceImpl implements ISysBuriedPointService {

    /**
     * 日志
     */
    protected final Logger logger = LoggerFactory.getLogger(this.getClass());

    @Autowired
    private SysBuriedPointMapper sysBuriedPointMapper;

    @Autowired
    private SysBuriedPointResultMapper sysBuriedPointResultMapper;

    @Autowired
    private SysUserEventBuriedPointMapper sysUserEventBuriedPointMapper;

    @Autowired
    private SysUserEventBuriedPointResultMapper sysUserEventBuriedPointResultMapper;

    @Autowired
    ISysUserEventBuriedPointService sysUserEventBuriedPointService;

    @Autowired
    ISysUserEventBuriedPointResultService sysUserEventBuriedPointResultService;

    @Autowired
    private ExerciseOrderMapper exerciseOrderMapper;

    @Autowired
    private IMechanismService mechanismService;

    @Autowired
    ICustomerService customerService;

    @Autowired
    ISysUserOrderBuriedPointResultService sysUserOrderBuriedPointResultService;

    /**
     * 查询埋点记录
     *
     * @param id 埋点记录主键
     * @return 埋点记录
     */
    @Override
    public SysBuriedPoint selectSysBuriedPointById(Long id) {
        return sysBuriedPointMapper.selectSysBuriedPointById(id);
    }

    /**
     * 查询埋点记录列表
     *
     * @param sysBuriedPoint 埋点记录
     * @return 埋点记录
     */
    @Override
    public List<SysBuriedPoint> selectSysBuriedPointList(SysBuriedPoint sysBuriedPoint) {
        return sysBuriedPointMapper.selectSysBuriedPointList(sysBuriedPoint);
    }

    @Override
    public Integer addBuriedPoint(HttpServletRequest request, BuriedPointParam buriedPointParam) {
        try {
            SysBuriedPoint sysBuriedPoint = constructSysBuriedPoint(request, buriedPointParam);
            return sysBuriedPointMapper.insertSysBuriedPoint(sysBuriedPoint);
        } catch (Exception e) {
            // AsyncManager.me().execute(AsyncFactory.recordLogininfor("username", Constants.LOGIN_FAIL,
            //         MessageUtils.message("user.password.retry.limit.exceed", 1, 1)));
            logger.error("新增埋点记录异常", e);
            return null;
        }
    }

    @Override
    public int addUserEventBuriedPoint(HttpServletRequest request, UserEventBuriedPointParam userEventBuriedPointParam) {
        Customer customer = CommonUtils.getCustomerByRequest(request);
        SysUserEventBuriedPoint sysUserEventBuriedPoint = constructorUserEventBuriedPoint(customer, userEventBuriedPointParam);
        return sysUserEventBuriedPointMapper.insertSysUserEventBuriedPoint(sysUserEventBuriedPoint);
    }

    @Override
    public UserOnlineTimeVO getUserOnlineTime(UserEventBuriedPointQueryParam userEventBuriedPointQueryParam) {
        userEventBuriedPointQueryParam = handleUserEventBuriedPointQueryParam(userEventBuriedPointQueryParam);
        UserOnlineTimeVO userOnlineTimeVO = sysUserEventBuriedPointResultMapper.getUserOnlineTimeSum(userEventBuriedPointQueryParam);
        handleUserOnlineTimeVO(userOnlineTimeVO);
        return userOnlineTimeVO;
    }

    @Override
    public List<UserOnlineTimeDetail> getUserOnlineTimeDetailList(UserEventBuriedPointQueryParam userEventBuriedPointQueryParam) {
        userEventBuriedPointQueryParam = handleUserEventBuriedPointQueryParam(userEventBuriedPointQueryParam);
        List<UserOnlineTimeDetail> userOnlineTimeDetailList = sysUserEventBuriedPointResultMapper.getUserOnlineTime(userEventBuriedPointQueryParam);
        handleOnlineTimeDetailList(userOnlineTimeDetailList);
        return userOnlineTimeDetailList;
    }

    @Override
    public UserOnlineTimeStatusVO getUserOnlineTimeStatus(UserEventBuriedPointQueryParam userEventBuriedPointQueryParam) {
        userEventBuriedPointQueryParam = handleUserEventBuriedPointQueryParam(userEventBuriedPointQueryParam);
        UserOnlineTimeStatusVO userOnlineTimeVO = sysUserOrderBuriedPointResultService.getUserOnlineTimeSumStatus(userEventBuriedPointQueryParam);
        handleStatusUserOnlineTimeVO(userOnlineTimeVO);
        return userOnlineTimeVO;
    }

    @Override
    public List<UserOnlineTimeStatusDetail> getUserOnlineTimeStatusDetailList(UserEventBuriedPointQueryParam userEventBuriedPointQueryParam) {
        userEventBuriedPointQueryParam = handleUserEventBuriedPointQueryParam(userEventBuriedPointQueryParam);
        List<UserOnlineTimeStatusDetail> userOnlineTimeDetailList = sysUserOrderBuriedPointResultService.getUserOnlineTimeStatus(userEventBuriedPointQueryParam);
        handleUserOnlineTimeStatusDetail(userOnlineTimeDetailList);
        return userOnlineTimeDetailList;
    }

    private UserEventBuriedPointQueryParam handleUserEventBuriedPointQueryParam(UserEventBuriedPointQueryParam userEventBuriedPointQueryParam)
    {
        if (null == userEventBuriedPointQueryParam) {
            return null;
        }
        Integer ageGroup = userEventBuriedPointQueryParam.getAgeGroup();
        AgeGroupEnum ageGroupEnum = AgeGroupEnum.getAgeGroupByCode(ageGroup);
        userEventBuriedPointQueryParam.setMinAge(ageGroupEnum.getMinAge());
        userEventBuriedPointQueryParam.setMaxAge(ageGroupEnum.getMaxAge());
        Integer sex = NumberConstants.NEGATIVE_ONE == userEventBuriedPointQueryParam.getSex()?null:userEventBuriedPointQueryParam.getSex();
        userEventBuriedPointQueryParam.setSex(sex);
        Integer integerStatus = userEventBuriedPointQueryParam.getStatus();
        if (null != userEventBuriedPointQueryParam.getStatus() && NumberConstants.NEGATIVE_ONE == userEventBuriedPointQueryParam.getStatus()) {
            integerStatus = null;
        }
        userEventBuriedPointQueryParam.setStatus(integerStatus);
        if (null!=userEventBuriedPointQueryParam.getStatus()){
            Integer status = userEventBuriedPointQueryParam.getStatus();
            ExerciseOrder exerciseOrder = new ExerciseOrder();
            PayStatus payStatus = PayStatus.getPayStatusByCode(status);
            exerciseOrder.setStatus(payStatus);
            List<ExerciseOrder> exerciseOrderList = exerciseOrderMapper.selectExerciseOrderList(exerciseOrder);
            List<String> orderNoList = exerciseOrderList.stream().map(item -> item.getOrderId()).collect(Collectors.toList());
            if (CollectionUtils.isNotEmpty(orderNoList)){
                if (PayStatus.Finish.equals(payStatus)) {
                    orderNoList.add("");
                }
                String orderNos = String.join(PunctuationConstants.COMMA, orderNoList);
                userEventBuriedPointQueryParam.setOrderNos(orderNos);
            }
        }

        return userEventBuriedPointQueryParam;
    }

    private void handleStatusUserOnlineTimeVO(UserOnlineTimeStatusVO userOnlineTimeVO) {
        if (null == userOnlineTimeVO) {
            return;
        }
        if (null != userOnlineTimeVO.getSecondTotalOnlineTime() && null != userOnlineTimeVO.getTotalPerson()) {
            double minute = DateUtils.getMinute(userOnlineTimeVO.getSecondTotalOnlineTime());
            userOnlineTimeVO.setMinuteOnlineTime(minute);
            double avgOnlineTime = minute / userOnlineTimeVO.getTotalPerson();
            avgOnlineTime = handleDoubleValue(avgOnlineTime);
            userOnlineTimeVO.setAvgOnlineTime(avgOnlineTime);
        }
        handleUserOnlineTimeStatusDetail(userOnlineTimeVO.getUserOnlineTimeDetailList());
    }

    private void handleUserOnlineTimeStatusDetail(List<UserOnlineTimeStatusDetail> userOnlineTimeDetailList) {
        if (CollectionUtils.isNotEmpty(userOnlineTimeDetailList)) {
            for (UserOnlineTimeStatusDetail userOnlineTimeDetail : userOnlineTimeDetailList) {
                String sex = userOnlineTimeDetail.getSex();
                userOnlineTimeDetail.setSex(SexEnum.getSexNameByCode(sex));
                Double onlineTime = userOnlineTimeDetail.getOnlineTime();
                onlineTime = DateUtils.getMinute(new Double(onlineTime).longValue());
                userOnlineTimeDetail.setOnlineTime(onlineTime);
                Integer onlineDays = userOnlineTimeDetail.getOnlineDays();
                double avgTime = onlineTime / onlineDays;
                avgTime = handleDoubleValue(avgTime);
                userOnlineTimeDetail.setAvgOnlineTime(avgTime);
                String status = userOnlineTimeDetail.getStatus();
                status = StringUtils.isNotBlank(status)? PayStatus.getPayStatusInfoByCode( Integer.valueOf(status) ):null;
                userOnlineTimeDetail.setStatus(status);
            }
        }
    }

    private UserOnlineTimeDetail getUserOnlineTimeDetail(Long customerId,String orderNos,List<UserOnlineTimeDetail> userOnlineTimeDetailList)
    {
        HashSet<String> orderSet = Sets.newHashSet(orderNos.split(PunctuationConstants.COMMA));
        List<UserOnlineTimeDetail> onlineTimeList = userOnlineTimeDetailList.stream().filter(item -> orderSet.contains(item.getOrderNo()) && item.getCustomerId().equals(customerId)).collect(Collectors.toList());
        UserOnlineTimeDetail onlineTime = onlineTimeList.get(0);
        UserOnlineTimeDetail userOnlineTimeDetail= new UserOnlineTimeDetail();
        BeanUtils.copyProperties(onlineTime,userOnlineTimeDetail);
        userOnlineTimeDetail.setStatus(PayStatus.Exercise.getInfo());
        //BigDecimal planTotalWorkTime = preSalesTaskVos.stream()
        //        // 将user对象的age取出来map为Bigdecimal
        //        .map(PreSalesTaskVo::getPlanWorkTime)
        //        // 使用reduce()聚合函数,实现累加器
        //        .reduce(BigDecimal.ZERO,BigDecimal::add);
        String sex = userOnlineTimeDetail.getSex();
        userOnlineTimeDetail.setSex(SexEnum.getSexNameByCode(sex));
        Double totalOnlineTime = 0d;// onlineTimeList.stream().map(item -> item.getOnlineTime()).filter(item -> null != item).reduce(0, BigDecimal::add);
        Double totalOnlineDays = 0d;// onlineTimeList.stream().map(item -> item.getOnlineDays()).filter(item -> null != item).reduce(0, BigDecimal::add);
        double avgOnlineTime = totalOnlineTime / totalOnlineDays;
        avgOnlineTime=handleDoubleValue(avgOnlineTime);
        userOnlineTimeDetail.setOnlineTime(totalOnlineTime);
        userOnlineTimeDetail.setAvgOnlineTime(avgOnlineTime);

        return userOnlineTimeDetail;
    }

    private SysUserOrderBuriedPointResult getSysUserOrderBuriedPointResult(Long customerId,String orderNos,List<UserOnlineTimeDetail> userOnlineTimeDetailList)
    {
        SysUserOrderBuriedPointResult userOrderBuriedPointResult= new SysUserOrderBuriedPointResult();
        HashSet<String> orderSet = Sets.newHashSet(orderNos.split(PunctuationConstants.COMMA));
        List<UserOnlineTimeDetail> onlineTimeList = userOnlineTimeDetailList.stream().filter(item -> orderSet.contains(item.getOrderNo()) && item.getCustomerId().equals(customerId)).collect(Collectors.toList());
        if (CollectionUtils.isEmpty(onlineTimeList)){
            return null;
        }
        UserOnlineTimeDetail onlineTime = onlineTimeList.get(0);
        BeanUtils.copyProperties(onlineTime,userOrderBuriedPointResult);
        userOrderBuriedPointResult.setAge(Long.valueOf(onlineTime.getAge()));
        userOrderBuriedPointResult.setSex(Long.valueOf(onlineTime.getSex()));
        userOrderBuriedPointResult.setStatus(PayStatus.Exercise.getCode());
        //String sex = userOnlineTimeDetail.getSex();
        //userOnlineTimeDetail.setSex(SexEnum.getSexNameByCode(sex));
        Double totalOnlineTime = onlineTimeList.stream().mapToDouble(item -> item.getOnlineTime()).sum();
        Integer totalOnlineDays = onlineTimeList.stream().mapToInt(item -> item.getOnlineDays()).sum();

        userOrderBuriedPointResult.setOnlineTime(new Double(totalOnlineTime).longValue());
        userOrderBuriedPointResult.setOnlineDays(new Integer(totalOnlineDays).longValue());
        userOrderBuriedPointResult.setCreateTime(DateUtils.getNowDate());

        return userOrderBuriedPointResult;
    }

    private void handleUserOnlineTimeVO(UserOnlineTimeVO userOnlineTimeVO) {
        if (null == userOnlineTimeVO) {
            return;
        }

        if (null != userOnlineTimeVO.getSecondTotalOnlineTime() && null != userOnlineTimeVO.getTotalPerson()) {
            double minute = DateUtils.getMinute(userOnlineTimeVO.getSecondTotalOnlineTime());
            userOnlineTimeVO.setMinuteOnlineTime(minute);
            double avgOnlineTime = minute / userOnlineTimeVO.getTotalPerson();
            avgOnlineTime = handleDoubleValue(avgOnlineTime);
            userOnlineTimeVO.setAvgOnlineTime(avgOnlineTime);
        }

        handleOnlineTimeDetailList(userOnlineTimeVO.getUserOnlineTimeDetailList());
        //        if (CollectionUtils.isNotEmpty(userOnlineTimeVO.getUserOnlineTimeDetailList())) {
        //            List<UserOnlineTimeDetail> userOnlineTimeDetailList = userOnlineTimeVO.getUserOnlineTimeDetailList();
        //            for (UserOnlineTimeDetail userOnlineTimeDetail : userOnlineTimeDetailList) {
        //                String sex = userOnlineTimeDetail.getSex();
        //                userOnlineTimeDetail.setSex(SexEnum.getSexNameByCode(sex));
        //                Double onlineTime = userOnlineTimeDetail.getOnlineTime();
        //                Integer onlineDays = userOnlineTimeDetail.getOnlineDays();
        //                double avgTime = onlineTime / onlineDays;
        //                avgTime = handleDoubleValue(avgTime);
        //                userOnlineTimeDetail.setAvgOnlineTime(avgTime);
        //            }
        //        }
    }

    private void handleOnlineTimeDetailList(List<UserOnlineTimeDetail> userOnlineTimeDetailList){
        if (CollectionUtils.isNotEmpty(userOnlineTimeDetailList)) {
            for (UserOnlineTimeDetail userOnlineTimeDetail : userOnlineTimeDetailList) {
                String sex = userOnlineTimeDetail.getSex();
                userOnlineTimeDetail.setSex(SexEnum.getSexNameByCode(sex));
                Double onlineTime = userOnlineTimeDetail.getOnlineTime();
                onlineTime= DateUtils.getMinute(new Double(onlineTime).longValue());
                onlineTime= handleDoubleValue(onlineTime);
                userOnlineTimeDetail.setOnlineTime(onlineTime);
                Integer onlineDays = userOnlineTimeDetail.getOnlineDays();
                double avgTime = onlineTime / onlineDays;
                avgTime = handleDoubleValue(avgTime);
                userOnlineTimeDetail.setAvgOnlineTime(avgTime);
            }
        }
    }

    private Double handleDoubleValue(Double value){
        if (null==value){
            return null;
        }
        BigDecimal b = new BigDecimal(value);
        double result = b.setScale(1, BigDecimal.ROUND_HALF_UP).doubleValue();
        return result;
    }

    @Override
    public UserOnlineFrequencyVO getUserOnlineFrequency(UserEventBuriedPointQueryParam userEventBuriedPointQueryParam) {
        userEventBuriedPointQueryParam = handleUserEventBuriedPointQueryParam(userEventBuriedPointQueryParam);
        UserOnlineFrequencyVO userOnlineFrequencyVO = sysUserEventBuriedPointResultMapper.getUserFrequencyTimeSum(userEventBuriedPointQueryParam);
        return userOnlineFrequencyVO;
    }

    @Override
    public List<UserOnlineFrequencyDetail> getUserOnlineFrequencyDetailList(UserEventBuriedPointQueryParam userEventBuriedPointQueryParam) {
        userEventBuriedPointQueryParam = handleUserEventBuriedPointQueryParam(userEventBuriedPointQueryParam);
        List<UserOnlineFrequencyDetail> userFrequencyTimeList = sysUserEventBuriedPointResultMapper.getUserFrequencyTime(userEventBuriedPointQueryParam);
        handleUserFrequencyTimeList(userFrequencyTimeList);
        return userFrequencyTimeList;
    }

    void handleUserFrequencyTimeList(List<UserOnlineFrequencyDetail> userFrequencyTimeList){
        if (CollectionUtils.isNotEmpty(userFrequencyTimeList)) {
            for (UserOnlineFrequencyDetail userOnlineFrequencyDetail : userFrequencyTimeList) {
                String sex = userOnlineFrequencyDetail.getSex();
                userOnlineFrequencyDetail.setSex(SexEnum.getSexNameByCode(sex));
            }
        }
    }

    @Override
    public UserOnlineFrequencyStatusVO getUserOnlineFrequencyStatus(UserEventBuriedPointQueryParam userEventBuriedPointQueryParam) {
        userEventBuriedPointQueryParam = handleUserEventBuriedPointQueryParam(userEventBuriedPointQueryParam);
        UserOnlineFrequencyStatusVO userOnlineFrequencyVO = sysUserOrderBuriedPointResultService.getUserFrequencyTimeSumStatus(userEventBuriedPointQueryParam);
        return userOnlineFrequencyVO;
    }

    @Override
    public List<UserOnlineFrequencyStatusDetail> getUserOnlineFrequencyDetailStatusList(UserEventBuriedPointQueryParam userEventBuriedPointQueryParam) {
        userEventBuriedPointQueryParam = handleUserEventBuriedPointQueryParam(userEventBuriedPointQueryParam);
        List<UserOnlineFrequencyStatusDetail> userFrequencyTimeList = sysUserOrderBuriedPointResultService.getUserFrequencyTimeStatus(userEventBuriedPointQueryParam);
        handleUserFrequencyTimeStatusList(userFrequencyTimeList);
        return userFrequencyTimeList;
    }

    void handleUserFrequencyTimeStatusList(List<UserOnlineFrequencyStatusDetail> userFrequencyTimeList){
        if (CollectionUtils.isNotEmpty(userFrequencyTimeList)) {
            for (UserOnlineFrequencyStatusDetail userOnlineFrequencyDetail : userFrequencyTimeList) {
                String sex = userOnlineFrequencyDetail.getSex();
                userOnlineFrequencyDetail.setSex(SexEnum.getSexNameByCode(sex));

                String status = userOnlineFrequencyDetail.getStatus();
                status = StringUtils.isNotBlank(status)? PayStatus.getPayStatusInfoByCode( Integer.valueOf(status) ):null;
                userOnlineFrequencyDetail.setStatus(status);
            }
        }
    }

    @Override
    public SysUserEventBuriedPoint constructorUserEventBuriedPoint(Customer customer, UserEventBuriedPointParam userEventBuriedPointParam)
    {
        SysUserEventBuriedPoint sysUserEventBuriedPoint = new SysUserEventBuriedPoint();
        BeanUtils.copyProperties(userEventBuriedPointParam,sysUserEventBuriedPoint);
        sysUserEventBuriedPoint.setDate(DateUtils.getDate());
        sysUserEventBuriedPoint.setCustomerId(customer.getCustomerId());
        sysUserEventBuriedPoint.setCustomerName(customer.getNickName());
        String orderNo = getOrderNo(customer.getCustomerId());
        sysUserEventBuriedPoint.setOrderNo(orderNo);
        sysUserEventBuriedPoint.setCreateTime(DateUtils.getNowDate());

        return sysUserEventBuriedPoint;
    }

    private String getOrderNo(Long customerId)
    {
        if (null==customerId){
            return "";
        }
        ExerciseOrder exerciseOrder = new ExerciseOrder();
        exerciseOrder.setCustomerId(customerId);
        exerciseOrder.setStatus(PayStatus.Exercise);
        List<ExerciseOrder> exerciseOrderList = exerciseOrderMapper.selectExerciseOrderList(exerciseOrder);
        if (CollectionUtils.isEmpty(exerciseOrderList)){
            return "";
        }
        return exerciseOrderList.get(0).getOrderId();
    }

    @Override
    public List<PayTransformVO> getPayTransform(BuriedPointQuery buriedPointQuery) {
        List<PayTransformVO> payTransformVOList = sysBuriedPointResultMapper.getPayTransformList(buriedPointQuery);
        if (CollectionUtils.isNotEmpty(payTransformVOList)){
            return payTransformVOList.stream().filter(item -> !Constants.ORG_NAME_BURIED_POINT_DAY_SUM.equals(item.getOrgName())).collect(Collectors.toList());
        }
        return payTransformVOList;
    }

    public List<RemainResultVO> getRemainResultList(String date) {
        return sysBuriedPointMapper.getRemainResultList(date);
    }

    @Override
    public RemainVO getRemainInfo(BuriedPointQuery buriedPointQuery) {
        checkBuriedPointQueryParam(buriedPointQuery);
        //汇总
        RemainVO remainVO = sysBuriedPointResultMapper.getRemainInfo(buriedPointQuery);
        if (null==remainVO){
            return null;
        }
        //明细
        RemainTable remainTable = getRemainTable(buriedPointQuery);
        remainVO.setRemainTable(remainTable);

        return remainVO;
    }

    @Override
    public void getDynamicRemainInfo(HttpServletResponse response, BuriedPointQuery buriedPointQuery)
    {
        //明细
        RemainTable remainTable = getRemainTable(buriedPointQuery);
        String fileName = RuoYiConfig.getProfile() + File.separator + "export.xls";
        List<Map<String, String>> lstData = new ArrayList<>();
        for (int i = 0; i < remainTable.getRowData().size(); i++)
        {
            Map<String, String> mRow = remainTable.getRowData().get(i);
            Map<String, String> mNewRow = new LinkedHashMap<>();
            for (Map.Entry<String, String> entry : mRow.entrySet())
            {
                ColumnData column = remainTable.getColumnData().stream().filter(item -> item.getName().equals(entry.getKey())).findFirst().orElse(null);
                if (column != null)
                {
                    if (StringUtils.isNullOrEmpty(column.getLabel()))
                    {
                        mNewRow.put("日期",entry.getValue());
                    }else
                    {
                        mNewRow.put(column.getLabel(),entry.getValue());
                    }
                }
            }
            lstData.add(mNewRow);
        }
        ExcelWriter excelWriter = ExcelUtil.getWriter(new File(fileName));
        excelWriter.write(lstData);
        excelWriter.close();
        CommonUtils.exportExcel(response, fileName);
    }

    private void checkBuriedPointQueryParam(BuriedPointQuery buriedPointQuery) {
        Assert.state(StringUtils.isNotBlank(buriedPointQuery.getStartTime()), "开始日期不能为空");
        Assert.state(StringUtils.isNotBlank(buriedPointQuery.getEndTime()), "结束日期不能为空");
    }

    @Override
    public List<PayInfoVO> getPayInfo(BuriedPointQuery buriedPointQuery) {
        List<PayInfoVO> payInfoVOList = sysBuriedPointResultMapper.getPayInfo(buriedPointQuery);
        if (CollectionUtils.isNotEmpty(payInfoVOList)){
            return payInfoVOList.stream().filter(item -> !Constants.ORG_NAME_BURIED_POINT_DAY_SUM.equals(item.getOrgName())).collect(Collectors.toList());
        }
        return payInfoVOList;
    }

    @Override
    public List<TrainInfoVO> getTrainInfo(BuriedPointQuery buriedPointQuery) {
        List<TrainInfoVO> trainInfoVOList= sysBuriedPointResultMapper.getTrainInfo(buriedPointQuery);
        if (CollectionUtils.isNotEmpty(trainInfoVOList)){
            return trainInfoVOList.stream().filter(item->!Constants.ORG_NAME_BURIED_POINT_DAY_SUM.equals(item.getOrgName())).collect(Collectors.toList());
        }
        return trainInfoVOList;
    }

    @Override
    public List<SysBuriedPointVO> getSysBuriedPointList(BuriedPointQuery buriedPointQuery) {
        List<SysBuriedPoint> sysBuriedPointList = sysBuriedPointMapper.getSysBuriedPointList(buriedPointQuery);
        List<SysBuriedPointVO> sysBuriedPointVOList = getSysBuriedPointVO(sysBuriedPointList);
        return sysBuriedPointVOList;
    }

    @Override
    public List<SysBuriedPoint> getBuriedPointList(BuriedPointQuery buriedPointQuery) {
        return sysBuriedPointMapper.getSysBuriedPointList(buriedPointQuery);
    }


    public List<SysBuriedPointVO> getSysBuriedPointVO(List<SysBuriedPoint> sysBuriedPointList) {
        if (CollectionUtils.isEmpty(sysBuriedPointList)) {
            return null;
        }
        List<BuriedPointPath> buriedPointList = BuriedPointPath.getBuriedPointList();
        List<SysBuriedPointVO> list = new ArrayList<>();
        SysBuriedPointVO sysBuriedPointVO = null;
        for (SysBuriedPoint sysBuriedPoint : sysBuriedPointList) {
            sysBuriedPointVO = new SysBuriedPointVO();
            BeanUtils.copyProperties(sysBuriedPoint, sysBuriedPointVO);
            sysBuriedPointVO.setStrCreateTime(DateUtils.getFormatDate(sysBuriedPointVO.getCreateTime(), DateUtils.YYYY_MM_DD_HH_MM_SS));
            BuriedPointPath sysBuriedPath = getSysBuriedPoint(buriedPointList, sysBuriedPoint.getSection(), sysBuriedPoint.getModule(), sysBuriedPoint.getFunction());
            if (null == sysBuriedPath) {
                logger.warn("未查询到埋点路径，入参section{} module{} function{}", sysBuriedPoint.getSection(), sysBuriedPoint.getModule(), sysBuriedPoint.getFunction());
            } else {
                sysBuriedPointVO.setSectionName(sysBuriedPath.getSectionName());
                sysBuriedPointVO.setModuleName(sysBuriedPath.getModuleName());
                sysBuriedPointVO.setFunctionName(sysBuriedPath.getFunctionName());
            }
            list.add(sysBuriedPointVO);
        }
        return list;
    }

    @Override
    public void insertUserEventBuriedPointResult(String date) {
        long ts = DateUtils.getTimeMillis();
        try{
            logger.info("{},新增用户事件埋点统计结果开始,日期{}", ts, date);
            SysUserEventBuriedPointResult buriedPoint = new SysUserEventBuriedPointResult();
            buriedPoint.setDate(date);

            List<Long> customerIdList = sysUserEventBuriedPointResultService.selectCustomerIdList(buriedPoint);
            if (CollectionUtils.isEmpty(customerIdList)) {
                return;
            }
            List<SysUserEventBuriedPointResult> userEventBuriedPointResultList = new ArrayList<>();
            for (Long customerId : customerIdList) {
                SysUserEventBuriedPoint sysUserEventBuriedPoint=new SysUserEventBuriedPoint();
                sysUserEventBuriedPoint.setCustomerId(customerId);
                sysUserEventBuriedPoint.setDate(date);
                List<SysUserEventBuriedPoint> userEventBuriedPointList = sysUserEventBuriedPointService.selectSysUserEventBuriedPointList(sysUserEventBuriedPoint);
                List<SysUserEventBuriedPointResult> list = constructUserEventBuriedList(userEventBuriedPointList);
                userEventBuriedPointResultList.addAll(list);
            }

            //for (SysUserEventBuriedPointResult userEventBuriedPointResult : userEventBuriedPointResultList) {
            //    sysUserEventBuriedPointResultService.insertSysUserEventBuriedPointResult(userEventBuriedPointResult);
            //}
            //批量新增
            logger.info("{}，新增用户订单埋点统计结果开始================",   ts);
            int count = sysUserEventBuriedPointResultService.batchInsertSysUserEventBuriedPointResult(userEventBuriedPointResultList);
            logger.info("{}，新增用户订单埋点统计结果结束，新增数据条数{}==================",  ts, count);


            logger.info("{},新增用户事件埋点统计结果结束", ts);

            //新增用户订单埋点统计结果
            insertUserOrderBuriedList(ts);
        } catch (Exception e) {
            logger.error("{},新增用户事件埋点统计结果异常", ts, e);
        }

    }

    private void insertUserOrderBuriedList(Long ts) {
        try {
            logger.info("{},新增用户订单埋点统计结果开始", ts);

            logger.info("{},删除用户订单埋点统计结果开始", ts);
            int deleteResult = sysUserOrderBuriedPointResultService.deleteSysUserOrderBuriedPointResultById(null);
            logger.info("{},删除用户订单埋点统计结果结束，结果{}", ts,deleteResult);

            List<ExerciseOrderResult> exerciseOrderList = exerciseOrderMapper.getExerciseOrderList();
            Set<Long> customerIdSet = exerciseOrderList.stream().map(item -> item.getCustomerId()).collect(Collectors.toSet());
            List<Long> customerIdList = new ArrayList<>(customerIdSet);
            List<List<Long>> lists = ListUtil.averageAssign(customerIdList, 100);
            for (List<Long> idList : lists) {
                List<SysUserOrderBuriedPointResult> userOrderBuriedPointResultList = new ArrayList<>();
                UserEventBuriedPointQueryParam userEventBuriedPointQueryParam = new UserEventBuriedPointQueryParam();
                userEventBuriedPointQueryParam.setCustomerIdList(idList);
                List<UserOnlineTimeDetail> userOnlineTimeDetailList = sysUserEventBuriedPointResultMapper.getUserOnlineTimeStatus(userEventBuriedPointQueryParam);
                for (Long customerId : idList) {
                    Optional<ExerciseOrderResult> optionalOrderResult = exerciseOrderList.stream().filter(item -> item.getCustomerId().equals(customerId)).findFirst();
                    ExerciseOrderResult orderResult = optionalOrderResult.orElse(null);
                    String exerciseOrderNo = orderResult.getExerciseOrderNo();
                    if (StringUtils.isNotBlank(exerciseOrderNo)) {
                        SysUserOrderBuriedPointResult userOrderBuriedPointResult = getSysUserOrderBuriedPointResult(customerId, exerciseOrderNo, userOnlineTimeDetailList);
                        if (null != userOrderBuriedPointResult) {
                            userOrderBuriedPointResultList.add(userOrderBuriedPointResult);
                        }
                    }
                    String completedOrderNo = orderResult.getCompletedOrderNo();
                    if (StringUtils.isNotBlank(completedOrderNo)) {
                        SysUserOrderBuriedPointResult userOrderBuriedPointResult = getSysUserOrderBuriedPointResult(customerId, completedOrderNo, userOnlineTimeDetailList);
                        if (null != userOrderBuriedPointResult) {
                            userOrderBuriedPointResultList.add(userOrderBuriedPointResult);
                        }
                    }
                }
                //批量新增
                logger.info("{},{}批次,新增用户订单埋点统计结果开始================", idList, ts);
                int count = sysUserOrderBuriedPointResultService.batchInsertSysUserOrderBuriedPointResult(userOrderBuriedPointResultList);
                logger.info("{},{}批次,新增用户订单埋点统计结果结束，新增数据条数{}==================", idList, ts, count);
            }
            logger.info("{},新增用户订单埋点统计结果结束", ts);
        } catch (Exception e) {
            logger.error("{},新增用户订单埋点统计结果异常", ts, e);
        }
    }

    private List<SysUserEventBuriedPointResult> constructUserEventBuriedList( List<SysUserEventBuriedPoint> list)
    {
        //一个用户一个用户生成
        //List<SysUserEventBuriedPoint> list =new ArrayList<>();
        if (CollectionUtils.isEmpty(list)){
            return null;
        }

        List<SysUserEventBuriedPointResult> userEventBuriedPointResultList=new ArrayList<>();
        //某个订单，埋点时间倒序
        ArrayList<SysUserEventBuriedPoint> sysUserEventBuriedPointList = list.stream().collect(Collectors.collectingAndThen(Collectors.toCollection(() -> new TreeSet<>(Comparator.comparing(p -> p.getOrderNo()))), ArrayList::new));
        List<String> orderNoList  = sysUserEventBuriedPointList.stream().map(o -> o.getOrderNo()).collect(Collectors.toList());
        final int FIVE_MINUTES_SECONDS = 5 * 60;

        for (int i = 0; i < orderNoList.size(); i++) {
            int onlineTime = 0;
            String orderNo = orderNoList.get(i);
            List<SysUserEventBuriedPoint> userEventBuriedPointList = list.stream().filter(item -> item.getOrderNo().equals(orderNo)).collect(Collectors.toList());
            userEventBuriedPointList.sort(Comparator.comparing(SysUserEventBuriedPoint::getCreateTime).reversed());
            if (userEventBuriedPointList.size() == 1) {
                SysUserEventBuriedPointResult userEventBuriedPointResult = constructSysUserEventBuriedPointResult(userEventBuriedPointList.get(0), onlineTime);
                userEventBuriedPointResultList.add(userEventBuriedPointResult);
                continue;
            }

            for (int j = 0; j < userEventBuriedPointList.size()-1; j++) {
                SysUserEventBuriedPoint firstBuriedPoint = userEventBuriedPointList.get(j);
                SysUserEventBuriedPoint secondBuriedPoint = userEventBuriedPointList.get(j+1);
                int timeSpan = DateUtils.differentSecondByMillisecond(firstBuriedPoint.getCreateTime(), secondBuriedPoint.getCreateTime());
                if (timeSpan <= FIVE_MINUTES_SECONDS) {
                    onlineTime+=timeSpan;
                }
            }
            SysUserEventBuriedPointResult userEventBuriedPointResult = constructSysUserEventBuriedPointResult(userEventBuriedPointList.get(0), onlineTime);
            userEventBuriedPointResultList.add(userEventBuriedPointResult);
        }
        return userEventBuriedPointResultList;
    }

    private SysUserEventBuriedPointResult constructSysUserEventBuriedPointResult(SysUserEventBuriedPoint userEventBuriedPoint,long onlineTime)
    {
        if (null == userEventBuriedPoint) {
            return null;
        }
        SysUserEventBuriedPointResult userEventBuriedPointResult = new SysUserEventBuriedPointResult();
        BeanUtils.copyProperties(userEventBuriedPoint, userEventBuriedPointResult);
        Customer customer = customerService.selectCustomerByCustomerId(userEventBuriedPoint.getCustomerId());
        if (null!=customer) {
            String phone =  customer.getPhone() ;
            userEventBuriedPointResult.setPhone(phone);
            String orgNo = null != customer.getMechanismId() ? String.valueOf(customer.getMechanismId()) : null;
            userEventBuriedPointResult.setOrgNo(orgNo);
            //机构编号
            Mechanism mechanism = null;
            if (StringUtils.isNotBlank(orgNo)) {
                mechanism = mechanismService.selectMechanismByMechanismId(Long.valueOf(orgNo));
            }
            String orgName = null != mechanism ? mechanism.getMechanismName() : null;
            userEventBuriedPointResult.setOrgName(orgName);
            userEventBuriedPointResult.setAge(customer.getAge());
            userEventBuriedPointResult.setSex(customer.getSex());
        }
        userEventBuriedPointResult.setOnlineTime(onlineTime);
        userEventBuriedPointResult.setCreateTime(DateUtils.getNowDate());
        return userEventBuriedPointResult;
    }

    private BuriedPointPath getSysBuriedPoint(List<BuriedPointPath> sysBuriedPointList, String section, String module, String function) {
        if (CollectionUtils.isEmpty(sysBuriedPointList)
                || StringUtils.isBlank(section)
                || StringUtils.isBlank(module)
                || StringUtils.isBlank(function)
        ) {
            logger.warn("未查询到埋点路径，入参section{} module{} function{}", section, module, function);
            return null;
        }
        Optional<BuriedPointPath> optionalBuriedPointPath = sysBuriedPointList.stream()
                .filter(item -> item.getSection().equals(section))
                .filter(item -> item.getModule().equals(module))
                .filter(item -> item.getFunction().equals(function))
                .findFirst();
        BuriedPointPath buriedPointPath = optionalBuriedPointPath.orElse(null);
        return buriedPointPath;
    }

    private RemainTable getRemainTable(BuriedPointQuery buriedPointQuery) {
        RemainTable remainTable = new RemainTable();

        //列数据
        List<Integer> delayDayList = getDelayDayList(buriedPointQuery);
        List<ColumnData> columnDataList = getColumnData(delayDayList);
        remainTable.setColumnData(columnDataList);

        //行数据
        List<Map<String, String>> rowData = getRowData(buriedPointQuery, delayDayList);
        remainTable.setRowData(rowData);

        return remainTable;
    }

    // private List<Integer> getDelayDayList(BuriedPointQuery buriedPointQuery) {
    //
    //     List<Integer> delayDays = getDelayDays(buriedPointQuery);
    //     return delayDays;
    // }

    private List<ColumnData> getColumnData(List<Integer> delayDays) {
        List<ColumnData> columnDataList = new ArrayList<>();
        ColumnData columnData = new ColumnData();
        columnData.setName(Constants.DATE);
        columnData.setLabel("");
        columnDataList.add(columnData);

        for (Integer delayDay : delayDays) {
            columnData = new ColumnData();
            columnData.setName(String.valueOf(delayDay));
            columnData.setLabel(String.valueOf(delayDay));
            columnDataList.add(columnData);
        }
        return columnDataList;
    }

    private List<Map<String, String>> getRowData(BuriedPointQuery buriedPointQuery,List<Integer> delayDayList) {
        List<Map<String,String>> rowData=new ArrayList<>();
        LinkedHashMap<String,String> map = null;

        String startTime = buriedPointQuery.getStartTime();
        String endTime = buriedPointQuery.getEndTime();
        List<String> dateList = DateUtils.getDatesBetween(startTime, endTime);

        //查询每日支付用户
        SysBuriedPointResult sysBuriedPointResultParam = new SysBuriedPointResult();
        sysBuriedPointResultParam.setStartTime(buriedPointQuery.getStartTime());
        sysBuriedPointResultParam.setEndTime(buriedPointQuery.getEndTime());
        List<SysBuriedPointResult> sysBuriedPointResultList = sysBuriedPointResultMapper.selectSysBuriedPointResultList(sysBuriedPointResultParam);

        for (String date : dateList) {
            map =  new LinkedHashMap<>();
            //List<String> list = new ArrayList<>();
            //日期
            //list.add(date);
            map.put(Constants.DATE,date);

            //支付成功用户

            for (int i = 0; i < delayDayList.size(); i++) {
                Integer integer = delayDayList.get(i);
                Integer delayDay= integer-1;

                SysBuriedPointResult paySuccessSysBuriedPointResult = getSysBuriedPointResult(sysBuriedPointResultList, date);
                if (0==delayDay)
                {
                    String remainPaySuccessPageUserCount = "";
                    if (null != paySuccessSysBuriedPointResult && null != paySuccessSysBuriedPointResult.getRemainPaySuccessPageUserCount()) {
                        remainPaySuccessPageUserCount = String.valueOf(paySuccessSysBuriedPointResult.getRemainPaySuccessPageUserCount());
                    }
                    map.put(String.valueOf(integer),remainPaySuccessPageUserCount);
                }else {
                    String strDateAfter = DateUtils.getStrDateAfter(date, delayDay);
                    SysBuriedPointResult remainQingZhuSysBuriedPointResult = getSysBuriedPointResult(sysBuriedPointResultList, strDateAfter);
                    String remainUserCount = getRemainUserCount(paySuccessSysBuriedPointResult, remainQingZhuSysBuriedPointResult);
                    map.put(String.valueOf(integer), remainUserCount);
                }
            }
            //当日登录用户
            //for (Integer delayDay : delayDayList) {
            //
            //    list.add(remainUserCount);
            //    map.put(String.valueOf(delayDay),remainUserCount);
            //}
            rowData.add(map);
        }
        return rowData;
    }

    private String getRemainUserCount( SysBuriedPointResult paySuccessSysBuriedPointResult,SysBuriedPointResult  remainQingZhuSysBuriedPointResult)
    {
        if (null==paySuccessSysBuriedPointResult || null==remainQingZhuSysBuriedPointResult){
            return "";
        }
        String remainPaySuccessPageUser = paySuccessSysBuriedPointResult.getRemainPaySuccessPageUser();
        String remainWakeUpQingZhuUser = remainQingZhuSysBuriedPointResult.getRemainWakeUpQingZhuUser();
        if (StringUtils.isBlank(remainPaySuccessPageUser)|| StringUtils.isBlank(remainWakeUpQingZhuUser)){
            return "";
        }
        Set<String> remainPaySuccessPageUserList = Sets.newHashSet(remainPaySuccessPageUser.split(PunctuationConstants.COMMA));
        Set<String> remainWakeUpQingZhuUserList = Sets.newHashSet(remainWakeUpQingZhuUser.split(PunctuationConstants.COMMA));
        Set<String> intersection = remainPaySuccessPageUserList.stream().filter(remainWakeUpQingZhuUserList::contains).collect(Collectors.toSet());

        if (null==intersection){
            return "0";
        }
        return String.valueOf(intersection.size());
    }


    private SysBuriedPointResult getSysBuriedPointResult(List<SysBuriedPointResult> sysBuriedPointResultList, String date) {
        if (null == sysBuriedPointResultList) {
            return null;
        }
        Optional<SysBuriedPointResult> optionalSysBuriedPointResult = sysBuriedPointResultList.stream()
                .filter(item -> item.getDate().equals(date))
                .filter(item -> item.getOrgNo().equals(Constants.ORG_NO_BURIED_POINT_DAY_SUM))
                .findFirst();
        SysBuriedPointResult sysBuriedPointResult = optionalSysBuriedPointResult.orElse(null);
        return sysBuriedPointResult;
    }

    private List<Integer> getDelayDayList(BuriedPointQuery buriedPointQuery) {
        List<Integer> delayList = new ArrayList<>();
        Integer maxDelayDays = 30;
        String startTime = buriedPointQuery.getStartTime();
        Date date = DateUtils.parseDate(startTime);
        Date dateAfter = DateUtils.getDateAfter(date, maxDelayDays);
        Date now = new Date();
        if (DateUtils.compare(dateAfter, now)) {
            maxDelayDays = DateUtils.differentDaysByMillisecond(date, now);
        }
        for (Integer i = 1; i <= maxDelayDays; i++) {
            delayList.add(i);
        }
        return delayList;
    }

    private SysBuriedPoint constructSysBuriedPoint(HttpServletRequest request, BuriedPointParam buriedPointParam) {
        SysBuriedPoint sysBuriedPoint = new SysBuriedPoint();
        if (StringUtils.isNotBlank(buriedPointParam.getOrgNo())) {
            String orgNo = AesUtils.decryptHex(buriedPointParam.getOrgNo());
            buriedPointParam.setOrgNo(orgNo);
        }
        BeanUtils.copyProperties(buriedPointParam, sysBuriedPoint);
        Customer customer = null;
        try {
            customer = CommonUtils.getCustomerByRequest(request);
        } catch (Exception e) {
            logger.error("获取会员信息异常", e);
        }
        String ip = IpUtils.getIpAddr(request);
        sysBuriedPoint.setIp(ip);

        Long customerId = null == customer ? null : customer.getCustomerId();
        String customerName = null == customer ? null : customer.getNickName();
        Long mechanismId = null == customer ? null : customer.getMechanismId();
        String orgNo = buriedPointParam.getOrgNo();
        if (StringUtils.isBlank(orgNo) && null != mechanismId) {
            orgNo = String.valueOf(mechanismId);
        }
        Mechanism mechanism = null;
        if (StringUtils.isNotBlank(orgNo)) {
            mechanism = mechanismService.selectMechanismByMechanismId(Long.valueOf(orgNo));
        }
        String orgName = null != mechanism ? mechanism.getMechanismName() : null;
        Date nowDate = DateUtils.getNowDate();
        String strDate = DateUtils.getFormatDate(nowDate, DateUtils.YYYY_MM_DD);

        sysBuriedPoint.setCustomerId(customerId);
        sysBuriedPoint.setCustomerName(customerName);
        sysBuriedPoint.setOrgNo(orgNo);
        sysBuriedPoint.setOrgName(orgName);
        sysBuriedPoint.setCreateDate(strDate);
        sysBuriedPoint.setCreateTime(nowDate);

        return sysBuriedPoint;
    }

    /**
     * 新增埋点记录
     *
     * @param sysBuriedPoint 埋点记录
     * @return 结果
     */
    @Override
    public int insertSysBuriedPoint(SysBuriedPoint sysBuriedPoint) {
        sysBuriedPoint.setCreateTime(DateUtils.getNowDate());
        return sysBuriedPointMapper.insertSysBuriedPoint(sysBuriedPoint);
    }

    /**
     * 修改埋点记录
     *
     * @param sysBuriedPoint 埋点记录
     * @return 结果
     */
    @Override
    public int updateSysBuriedPoint(SysBuriedPoint sysBuriedPoint) {
        return sysBuriedPointMapper.updateSysBuriedPoint(sysBuriedPoint);
    }

    /**
     * 批量删除埋点记录
     *
     * @param ids 需要删除的埋点记录主键
     * @return 结果
     */
    @Override
    public int deleteSysBuriedPointByIds(Long[] ids) {
        return sysBuriedPointMapper.deleteSysBuriedPointByIds(ids);
    }

    /**
     * 删除埋点记录信息
     *
     * @param id 埋点记录主键
     * @return 结果
     */
    @Override
    public int deleteSysBuriedPointById(Long id) {
        return sysBuriedPointMapper.deleteSysBuriedPointById(id);
    }
}
